<template>
    <view class="flex flex-row" >
		<pickerPanelVue :immediateChange="props.immediateChange" :followTheme="props.followTheme" @end="emits('end')" @start="emits('start')" :dataKey="props.dataKey" @change="pickerChange($event,index)" :col="_colIndex[index]" v-for="(item,index) in _data" :data="item" :key="index" :height="props.height" class="flex-1"></pickerPanelVue>
    </view>
</template>
<script lang="ts" setup>
/**
 * 级联选择(滚选)
 * @description 嵌入在页面的级联选择(滚选)
 */
import { computed, PropType, watchEffect,ref, toRaw,onMounted,nextTick, watch, Ref } from 'vue';
import { columnsItem } from "./interface"
import pickerPanelVue from './picker-panel.vue';
/**
 * 事件说明
 * change 每一项滑动时会触发事件，并返回父索引levelIndex：当前第几列，子项目索引itemindex：当前列中的第几项被选中。
 * v-model:双向绑定返回当前选中的索引数组。
 * v-model:modelStr 单向输出索引字符串，与v-model区别一个显示索引，一个显示text文本，这个用处主要是用来绑定显示文本用，但与后台交互时可能只需索引。所以它只用来展示用比较方便。
 * start和end分别 为开始选择和结束选择触发的事件，目前在cli 8001结尾的版本（至2022/5/1此事件不会触发系hbx的bug）
 */
const emits = defineEmits(["change","update:modelValue","update:modelStr","end","start"])
const props = defineProps({
	followTheme: {
		type: [Boolean,String],
		default: true
	},
    height:{
		type:Number,
		default:450
	},
    //可v-model,每一列选中的索引值
	modelValue:{
		type:Array as PropType<Array<number>>,
		default:()=>[]
	},
	/**
	 * 注意：这里是单向输出显示的value值，而不是modelValue的index索引值。
	 * 这里主要是为了方便表单上页面的显示。如果真要保存到数据库，你应该保存modelValue的值。
	 */
	modelStr:{
		type:[String],
		default:''
	},
    //默认选中的索引值。
	defaultValue:{
		type:Array as PropType<Array<number>>,
		default:()=>[]
	},
    columns:{
        type:Array as PropType<Array<columnsItem>>,
		default:()=>[],
        required:true
    },
    //当columns项目中的data数据为对象时的key取值字段。
    dataKey:{
        type:String,
        default:"text"
    },
	//当前改变index项时，改变时执行的函数。如果返回false，将会阻止本次改变,可以是Promise
	//提供了即将改变的数据和将要改变到目标的数据
	//结构 为 from:{itemindex,levelIndex,data},to:{itemindex,levelIndex,data}。
	beforeChange:{
		type:[Boolean,Function],
		default:()=>false
	},
	immediateChange:{
		type:Boolean,
		default:false
	}
})
const _colIndex = ref([...props.defaultValue]);
const _data:Ref<Array<Array<columnsItem>>> = ref([])
const _modelStr = computed(()=>{
	let str:Array<string|number> = []
	_data.value.forEach((el,index)=>{
		let item = el[_colIndex.value[index]];
		if(typeof item =='undefined') return;
		str.push(item[props.dataKey]??"")
	})
	return str.join("/");
})

watch(()=>_colIndex.value,()=>{
	nextTick(()=>{
		emits("update:modelStr",_modelStr.value)
	})
},{deep:true})
//循环获取子级
function getIndexLoop(defaultindex=0,data:Array<columnsItem>):Array<Array<columnsItem>>{
	let ds:Array<Array<columnsItem>> = [];
	if(data.length==0) return [];
	if(typeof _colIndex.value[defaultindex] == 'undefined'){
		_colIndex.value.push(0)
	}
	let nowData = data[_colIndex.value[defaultindex]]
	if(!nowData){
		_colIndex.value[defaultindex] = 0;
		nowData = data[_colIndex.value[defaultindex]];
	}
	if(nowData&&nowData?.children&&Array.isArray(nowData?.children)&&nowData?.children?.length>0){
		ds.push(data)
		let dy = getIndexLoop(defaultindex+1,nowData?.children)
		ds = [...ds,...dy]
	}else{
		if(data?.length>0&&Array.isArray(data)&&data){
			ds.push(data)
			
		}
	}
	return ds;
}
_data.value = getIndexLoop(0,props.columns)

watch(()=>props.columns,()=>{
	_data.value = getIndexLoop(0,props.columns)
},{deep:true})
watch(()=>props.modelValue,()=>{
	_colIndex.value = props.modelValue;
	_data.value = getIndexLoop(0,props.columns)
},{deep:true})
//itemindex 子级索引
//levelIndex 父级索引
async function pickerChange(itemindex:number,levelIndex:number){
	
	let isActive = true;
	let toItem = _data.value[levelIndex][itemindex]
	const params = {
		from:{itemindex:_colIndex.value[levelIndex],levelIndex:levelIndex,data:_data.value[levelIndex][_colIndex.value[levelIndex]]},
		to:{itemindex:itemindex,levelIndex:levelIndex,data:toItem}
	}
	
	_colIndex.value.splice(levelIndex,1,itemindex)
	if (typeof props.beforeChange === 'function') {
		
		uni.showLoading({title:"...",mask:true})
		let p = await props.beforeChange(params);
		if(typeof p === 'function'){
			p = await p(params);
		}
		if (!p){
			isActive = false;
			nextTick(()=>{
				_colIndex.value.splice(levelIndex,1,params.from.itemindex)
			})
			uni.hideLoading();
		}
	}
	if(toItem?.disabled==true){
		isActive = false;
		nextTick(()=>{
			_colIndex.value.splice(levelIndex,1,params.from.itemindex)
		})
	}
	
	if(isActive){
		_data.value = getIndexLoop(0,props.columns)
		emits("change",levelIndex,itemindex)
		emits("update:modelValue",toRaw(_colIndex.value))
	}
	
}

nextTick(()=>{
	emits("update:modelValue",toRaw(_colIndex.value))
	emits("update:modelStr",_modelStr.value||props.modelStr)
})

</script>